home *** CD-ROM | disk | FTP | other *** search
-
- #import <appkit/appkit.h>
- #import <misckit/misckit.h>
- #import <misckit/MiscDateView.h>
-
- #import "Alexandra.h"
- #import "Composer.h"
- #import "NNTP.h"
- #import "descriptors.h"
- #import "ArticleViewControl.h"
- #import "ArticleSet.h"
- #import "NntpPanelControl.h"
- #import "plain-subject.h"
- #include <ctype.h>
- #include <dbkit/DBTableView.h>
-
- #define OK_POSTED 240
-
- static MiscList *myComposers;
- static XTDispatchAction *emacs_action;
- static XTDispatchAction *none_action;
-
- @implementation Composer
-
- //-----------------------------------------------------------
- // Klassen Methoden, Verwalten der Composer Liste
- //-----------------------------------------------------------
-
- + initialize
- {
- char buf[MAXPATHLEN + 1];
- const char *userBindings;
-
- if(self==[Composer class])
- {
- myComposers=[[MiscList alloc] init];
- emacs_action=[[XTDispatchAction alloc] init];
- none_action=[[XTDispatchAction alloc] init];
-
- if([[NXBundle mainBundle] getPath:buf forResource:"emacs" ofType:"keys"])
- [emacs_action loadFromFile:buf estream:nil];
-
- if(userBindings=[NXApp defaultValue:"KeyString"]){
- [emacs_action addBindings:userBindings estream:nil];
- [none_action addBindings:userBindings estream:nil];
- }
- }
- return self;
- }
-
-
- + newWindowForServer:(NNTP *)server;
- {
- Composer *new;
-
- new=[[self alloc] initForServer:server];
- [myComposers addObject:new];
- return new;
- }
-
-
- + removeComposer:(Composer *)composer;
- {
- [myComposers removeObject:composer];
- return self;
- }
-
-
- + killComposerForServer:(NNTP *)server;
- {
- Composer *c;
-
- for(c=[myComposers setLastObject];c;c=[myComposers setPreviousObject])
- if([c nntpServer]==server)
- [c free];
- return self;
- }
-
- + confirmTermination
- {
- int r1,r2;
- int j=[myComposers count];
- if(j>0)
- do{
- r1=NXRunAlertPanel("ALEXANDRA","There are unsend messages.","Review unsend","Quit anyway","Cancel");
- if(r1==NX_ALERTOTHER)
- return nil;
- else if(r1==NX_ALERTALTERNATE){
- int i;
- for(i=j-1;i>=0;i--)
- [[myComposers objectAt:i] free];
-
- return self;
- }
- else{
- int i;
- BOOL canceled=FALSE;
- for(i=j-1;i>=0;i--){
- id aComposer=[myComposers objectAt:i];
- [[aComposer window] makeKeyAndOrderFront:self];
- r2=NXRunAlertPanel("ALEXANDRA","Send this message?","Send","Don't send","Cancel");
- if(r2==NX_ALERTOTHER){
- canceled=TRUE;
- break;
- }
- else if(r2==NX_ALERTDEFAULT)
- [aComposer post:self];
- else
- [aComposer free];
- }
- if(canceled)
- j=[myComposers count];
- else
- return self;
- }
- } while(j>0);
-
- return self;
- }
- //-----------------------------------------------------------
- // INIT & FREE
- //-----------------------------------------------------------
-
- - initForServer:(NNTP *)theServer;
- {
- float char78Width;
- NXRect textFrame;
- NXRect windowFrame;
- NXAtom ids[]={[KVPair keyIdentifier],[KVPair valueIdentifier],NULL};
-
- if([NXApp loadNibSection:"Composer.nib" owner:self withNames:NO]==nil)
- EM_ERROR(EGENFileNotFound,"Composer.nib",NULL);
- [self setNntpServer:theServer];
- headerController=[[[MiscTableController alloc] init] setTableView:headerTable withIdentifiers:ids];
- [self getDefaults];
-
- char78Width=78*[[theText font] getWidthOf:"A"];
- [theText getFrame:&textFrame];
- [[theText window] getFrame:&windowFrame];
- char78Width+=NX_WIDTH(&windowFrame)-NX_WIDTH(&textFrame);
-
- [[theText window] sizeWindow:char78Width :NX_HEIGHT(&windowFrame)];
-
- if([NXApp defaultBoolValue:DEFAULT_APPEND_SIG]){
- NXStream *signatureFile;
- const char *home=NXHomeDirectory();
- char *filename;
-
- filename=(char *)NXZoneCalloc(MYZONE,(strlen(home)+12),sizeof(char));
- sprintf(filename,"%s/.signature",home);
-
- if((signatureFile=NXMapFile(filename,NX_READONLY))!=NULL){
- [theText readText:signatureFile];
- [theText setSel:0:0];
- [theText replaceSel:"\n-- \n"];
- [theText setSel:0:0];
- NXClose(signatureFile);
- }
- else
- NXRunAlertPanel("Alexandra","Cannot append signature."
- " File `~/.signature' not found.","Cancel",NULL,NULL);
- NXZoneFree(MYZONE,filename);
- }
-
-
- [[theText window] makeKeyAndOrderFront:self];
-
- return self;
- }
-
-
-
- - getDefaults
- {
- KVPair *emptypair=[[KVPair allocFromZone:MYZONE] init];
- char defname[200];
- const char *d;
- int i,n=[NXApp defaultIntValue:DEFAULT_XHEADER_COUNT];
-
- [headerController empty:nil];
- for(i=0;i<n;i++)
- {
- sprintf(defname,DEFAULT_XHEADERS,i+1);
- d=[NXApp defaultValue:defname];
- if(d)
- [headerController addRow:[[KVPair alloc] init:d delimiter:':']];
- else
- [headerController addRow:emptypair];
- }
- [emptypair free];
- return self;
- }
-
-
- - free
- {
- [[self class] removeComposer:self];
- [[[headerTable window] close] free];
- [[window close] free];
-
- if(subject!=NULL)
- free(subject);
- if(newsgroups!=NULL)
- free(newsgroups);
- if(references!=NULL)
- free(references);
- if(theQuotingStream!=NULL)
- NXCloseMemory(theQuotingStream,NX_FREEBUFFER);
- return [super free];
- }
-
-
- - awakeFromNib
- {
-
- if(strcmp([NXApp defaultValue:DEFAULT_KEY_BASE],"emacs")==0)
- local_action=emacs_action;
- else
- local_action=none_action;
-
- theText=[theText docView];
- [theText setMonoFont:YES];
- [theText setFont: [Font userFixedPitchFontOfSize:0
- matrix:NX_FLIPPEDMATRIX]];
-
- [theText setInitialAction:local_action];
- [headerForm setNextText:theText];
- return self;
- }
-
-
- //-----------------------------------------------------------
- // quoting
- //-----------------------------------------------------------
-
- - followup:sender
- {
- char *newSubject,*oldSubject;
- BOOL wasReply;
-
- if(subject==NULL)
- return self;
- oldSubject=plain_subject(subject,&wasReply);
- newSubject=(char *)NXZoneCalloc(MYZONE,(strlen(subject)+5),sizeof(char));
- sprintf(newSubject,"Re: %s",oldSubject);
- [subjectCell setStringValueNoCopy:newSubject shouldFree:YES];
-
- [newsgroupCell setStringValue:newsgroups];
- [followupButton setIcon:[followupButton altIcon]];
- [followupButton setTitle:[followupButton altTitle]];
- [followupButton setAction:@selector(includeArticle:)];
- if(strlen(references)>0)
- insert_refs=TRUE;
- return self;
- }
-
- - includeArticle:sender
- {
- char *buf;
- int len,maxlen;
-
- if(theQuotingStream!=NULL){
- NXGetMemoryBuffer(theQuotingStream,&buf,&len,&maxlen);
- [theText setSel:0:0];
- [theText replaceSel:buf length:len];
- }
- [followupButton setEnabled:FALSE];
- return self;
- }
-
- - post:sender
- {
- char month_name[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep",
- "Oct","Nov","Dec"};
- char mime_header[]="MIME-Version: 1.0\nContent-Type: text/plain; charset=iso-8859-1\nContent-Transfer-Encoding: 8bit\n";
- char *a2String;
- NXStream *theStream;
- long bodyPos;
- int textLength;
- int line;
- int pos;
- NXBreakArray *theBreaks=0;
- int nbreaks;
- NXLineDesc *breaks;
- BOOL asciiBody;
- BOOL userDefdFrom=NO;
- int statusCode;
- MiscList *headers;
- KVPair *pair;
-
- if([newsgroupCell stringValue][0]=='\0'){
- NXRunAlertPanel("ALEXANDRA","No Newsgroups header field body. Can't post.",NULL,NULL,NULL);
- return nil;
- }
- if([subjectCell stringValue][0]=='\0'){
- NXRunAlertPanel("ALEXANDRA","No Subject header field body. Can't post.",NULL,NULL,NULL);
- return nil;
- }
- if([theText textLength]==0){
- NXRunAlertPanel("ALEXANDRA","No article body. Can't post.",NULL,NULL,NULL);
- return nil;
- }
- if([expireButton state] && ([dateView isDateValid:self]==FALSE))
- return nil;
-
- [headerTable endEditing];
-
- theStream=NXOpenMemory(NULL,0,NX_READWRITE);
- NXSeek(theStream,0,NX_FROMSTART);
-
- //Write MIME-Header
- asciiBody=[self asciiBody];
- if(asciiBody==FALSE)
- NXPrintf(theStream,"%s",mime_header);
-
- // Write Newsgroups: header
- NXPrintf(theStream,"Newsgroups: %s\n",[newsgroupCell stringValue]);
-
- // Write Subject: header
- NXPrintf(theStream,"Subject: %s\n",[subjectCell stringValue]);
-
- // Write References: header
- if(insert_refs==TRUE)
- NXPrintf(theStream,"References: %s\n",references);
-
- headers=[headerController rows];
- for(pair=[headers setFirstObject]; pair; pair=[headers setNextObject])
- if([pair hasValue])
- {
- if(!strcasecmp([pair key],"from"))
- userDefdFrom=YES;
- NXPrintf(theStream,"%s: %s\n",[pair key],[pair value]);
- }
-
- // Write Expires: header
- if([expireButton state]){
- int day=[dateView getDay:self];
- const char *month=month_name[[dateView getMonth:self]-1];
- int year=[dateView getYear:self];
-
- NXPrintf(theStream,"Expires: %d %s %d 00:00:00 GMT\n",day,month,year);
- }
-
- if(!userDefdFrom){
- a2String=[[FromHeaderController new] validFromAddress];
- if(!a2String)
- {
- NXCloseMemory(theStream,NX_FREEBUFFER);
- return nil;
- }
- NXPrintf(theStream,"From: %s\n",a2String);
- free(a2String);
- }
- NXPrintf(theStream,"X-Newsreader: %s.app (%s)\n",
- [NXApp appName],[NXApp appVersion]);
-
- //Write end of header
- NXPutc(theStream,'\n');
- bodyPos=NXTell(theStream);
-
- /*write body*/
- textLength=[theText textLength];
- object_getInstanceVariable(theText, "theBreaks", (void **)&theBreaks);
- nbreaks = theBreaks->chunk.used/sizeof(NXLineDesc);
- breaks = theBreaks->breaks;
-
- for(pos=0,line=0;line<nbreaks && pos<textLength;line++) {
- int lineChange;
- int endParagraph;
- int len,nlen;
- char *buf,*realbuf;
-
- lineChange = breaks[line] & 0x8000;
- endParagraph = breaks[line] & 0x4000;
-
- len = breaks[line] & 0x3fff;
- buf = malloc(len+2);
- realbuf=buf;
- buf++;
- nlen = [theText getSubstring:buf start:pos length:len];
-
- if(buf[0]=='.'){
- buf--;
- nlen++;
- buf[0]='.';
- }
-
- if((nlen>0)&&(buf[nlen-1]!='\n')){
- if(buf[nlen-1]=='\0')
- buf[nlen-1]='\n';
- else{
- buf[nlen] = '\n';
- nlen++;
- }
- }
-
- NXWrite(theStream,buf,nlen);
- free(realbuf);
- pos+=len;
- if (lineChange!=0) {
- /* "if the line change bit is set, the descriptor is
- * the first field of a NXHeightChange...." */
- line += sizeof(NXHeightInfo) / sizeof(NXLineDesc);
- }
- }
-
- statusCode=[nntpServer postArticle:theStream];
- if(statusCode==OK_POSTED){
- [window close];
- NXCloseMemory(theStream,NX_FREEBUFFER);
- [self free];
- return self;
- }
-
- return nil;
- }
-
- - preparePostTo:(List *)newsgroupList selArticle:(Article *)anArticle
- inView:(ArticleViewControl *)controlView;
- {
- int i,j,strlength;
- char *newsgroup_str;
- char *ptr;
- const char *newsgroup;
- char *msg_id,*refs;
-
- //Make newsgrouplist string and set Newsgroups: field
- strlength=0;
- j=[newsgroupList count];
- for(i=0;i<j;i++)
- strlength += strlen([[newsgroupList objectAt:i] stringValue]);
- newsgroup_str=(char *)malloc((strlength+j)*sizeof(char));
- ptr=newsgroup_str;
- for(i=0;i<j;i++){
- newsgroup=[[newsgroupList objectAt:i] stringValue];
- strcpy(ptr,newsgroup);
- ptr+=strlen(newsgroup);
- if(i<j-1)
- *ptr=',';
- ptr++;
- }
- [newsgroupCell setStringValueNoCopy:newsgroup_str shouldFree:YES];
-
- //remember selected article fields
- subject=NULL;
- if(anArticle==nil)
- [followupButton setEnabled:FALSE];
- else{
- subject=NXCopyStringBuffer([anArticle header]->fieldBody[SUBJECT]);
-
- //where to followup?
- if([anArticle header]->fieldBody[FOLLOWUP_TO]!=NULL)
- newsgroups=NXCopyStringBuffer([anArticle header]->fieldBody[FOLLOWUP_TO]);
- else
- if([anArticle header]->fieldBody[NEWSGROUPS]!=NULL)
- newsgroups=NXCopyStringBuffer([anArticle header]->fieldBody[NEWSGROUPS]);
-
- //References field
- i=0; j=0;
- refs=[anArticle header]->fieldBody[REFS];
- msg_id=[anArticle header]->fieldBody[MSG_ID];
- if(refs!=NULL)
- i=strlen(refs);
- if(msg_id!=NULL)
- j=strlen(msg_id);
- references=(char *)malloc((i+j+3)*sizeof(char));
- references[0]='\0';
- if(refs!=NULL)
- strcpy(references,refs);
- if(msg_id!=NULL){
- if(strlen(references)>0)
- strcat(references," ");
- strcat(references,msg_id);
- }
- insert_refs=FALSE;
-
- // Copy article body
- theQuotingStream=NXOpenMemory(NULL,0,NX_READWRITE);
- if([anArticle header]->fieldBody[FROM]!=NULL)
- NXPrintf(theQuotingStream,"%s wrote:\n",[anArticle header]->fieldBody[FROM]);
- [controlView writeQuotedText:theQuotingStream];
- }
- //set DateViews date as today
- [dateView getTodaysDate:self];
-
- return self;
- }
-
- - window
- {
- return window;
- }
-
- - setNntpServer:(NNTP *)nntp
- {
- nntpServer=nntp;
- return self;
- }
-
-
- - (NNTP *)nntpServer;
- {
- return nntpServer;
- }
-
-
- - printText:sender
- {
- if([theText textLength]!=0){
- [[NXApp printInfo] setHorizPagination:NX_FITPAGINATION];
- [theText printPSCode:self];
- }
-
- return self;
- }
-
-
- - (BOOL)asciiBody
- {
- NXStream *textStream;
- int len,maxlen;
- char *p;
-
- textStream= NXOpenMemory(NULL,0,NX_WRITEONLY);
- [theText writeText:textStream];
- NXGetMemoryBuffer(textStream,&p,&len,&maxlen);
- for(;len>0;p++,len--)
- if(!NXIsAscii(*p))
- break;
- NXCloseMemory(textStream,NX_FREEBUFFER);
- return (len<=0);
- }
-
-
- - theText
- {
- return theText;
- }
-
-
- - windowWillClose:sender
- {
- if([theText textLength]!=0){
- int answer=NXRunAlertPanel("ALEXANDRA","Message was not posted.","Close Anyway", "Cancel",NULL);
- if(answer==NX_ALERTALTERNATE)
- return nil;
- }
- return [self free];
- }
-
-
- - windowWillMiniaturize:sender toMiniwindow:miniwindow
- {
- [sender setMiniwindowIcon:"respond"];
- return self;
- }
-
-
- - windowWillReturnFieldEditor:sender toObject:client
- {
- return [XText newFieldEditorFor:sender
- initialAction:local_action
- estream:nil];
- }
-
- - rot13:sender
- {
- char *buf;
- int i,j=[theText textLength];
-
- buf=malloc((j+2)*sizeof(char));
- [theText getSubstring:buf start:0 length:j];
- buf[j]='\0';
-
- for(i=0;i<j;i++) {
- if(islower(buf[i]))
- buf[i]=(((buf[i]-'a')+13)%26)+'a';
- else if(isupper(buf[i]))
- buf[i]=(((buf[i]-'A')+13)%26)+'A';
- }
-
- [theText setText:buf];
-
- free(buf);
-
- return self;
- }
-
-
-
-
-
- @end
-